import { isMyRoom } from '@/ayaka'
import FlagController, { FlagPrefix } from '@/modules/flag'
import { goTo } from '@/modules/move'
import { CreepBoostData } from '@/modules/structures/lab/types'
import SpawnController, { getCreeps } from '@/modules/structures/spawn'
import { CreepRoles, SpawnTask } from '@/modules/structures/spawn/types'
import { BattleConfig } from '@/setting'
import { getBodyPartTypes } from '@/utils/common'
import { levelBoostMap, ResourcePartMap } from '@/utils/constants'
import BattleCalc from './calc'

/**
 * 战斗孵化相关
 */
export default class BattleSpawn {
    /**
     * 获取可用战斗旗帜
     *
     * @returns 可用的战斗旗帜列表
     */
    public static getAvailableFlags(flags: Flag[]) {
        return flags.filter((flag) => {
            // 如果存在配置名
            if (flag.memory.config || flag._setPositioned) return true

            const { id } = flag.memory
            // 不存在对应的配置
            if (!BattleConfig[id]) return false
            // 删除旧旗帜，重新创建
            // 比如玩家插旗的时候是 team_E13S13_r1t3，那么读取到配置为 r1t3，删除该旗帜，重新创建旗帜如 team_E13S13_r1t3_51415125
            // 这是因为我们希望玩家插旗时只考虑配置，这样相同配置的旗帜名是相同的，所以需要改造一下
            FlagController.reCreateFlag(flag, {
                config: id,
                creeps: [],
                createTime: Game.time,
                ...BattleSpawn.getFlagExtraMemory(id),
            })

            return false
        })
    }

    /**
     * 初始化旗帜内存
     */
    public static getFlagExtraMemory(configName: string): Partial<FlagMemory> {
        const config = BattleConfig[configName]
        let hasWork = false

        config.forEach(({ body }) => {
            if (hasWork) return

            const partTypes = getBodyPartTypes(body)
            if (partTypes.includes(WORK)) {
                hasWork = true
            }
        })

        return {
            hasWork,
        }
    }

    /**
     * 持续战斗旗帜孵化战斗旗帜
     */
    public static continueSpawn(flags: Flag[]) {
        flags.forEach((flag) => {
            if (!flag.memory.config) {
                const { id } = flag.memory
                if (!BattleConfig[id]) return

                flag.memory.config = id
            }

            if (!isMyRoom(flag._belongRoom)) {
                flag.remove()
                return
            }

            const { interval = 1300, count = 10, wait, endTigger, lastFlagCreateTime } = flag.memory

            // 检查提前结束的触发条件
            const room = flag._room
            if (room) {
                if (endTigger === 'unclaim') {
                    if (!room.controller?.owner) {
                        flag.remove()
                        return
                    }
                } else if (endTigger === 'safemode') {
                    if (room.controller?.safeMode) {
                        flag.remove()
                        return
                    }
                } else if (endTigger === 'no-struct') {
                    if (!room.find(FIND_HOSTILE_STRUCTURES).length) {
                        flag.remove()
                        return
                    }
                }

                if (room.controller?.safeMode) {
                    flag.memory.wait = room.controller.safeMode
                    return
                }
            }

            if (count <= 0) {
                flag.remove()
                return
            }

            // 需要等待
            if (wait) {
                flag.memory.wait = wait - 1
                return
            }

            // 没到旗帜创建时间
            if (lastFlagCreateTime && Game.time - lastFlagCreateTime < interval) return

            const { belong, id } = flag.memory
            if (!belong || !id) return

            // 创建战斗旗帜
            const randomPos = FlagController.getCreateFlagPos(flag._belongRoom)
            if (!randomPos) return

            const name = FlagController.createFlag(
                randomPos,
                FlagPrefix.team,
                belong,
                id,
                flag.color,
                flag.secondaryColor,
                {
                    setPosition: `${flag.pos.x}/${flag.pos.y}/${flag.pos.roomName}`,
                },
            )

            if (typeof name === 'string') {
                flag.memory.lastFlagCreateTime = Game.time
                flag.memory.count = count - 1
            }
        })
    }

    /**
     * 根据旗帜配置孵化对应的作战单位，同时更新旗帜内存`_creeps`，当所有爬阵亡时删除旗帜
     *
     * @return 是否已经孵化完成
     */
    public static spawnCreeps(flag: Flag) {
        // 主房没了，移除旗帜
        if (!flag._belongRoom) {
            flag.remove()
            return false
        }

        const creeps = getCreeps(flag._belongRoom, flag.memory.creeps)
        flag._creeps = creeps

        if (flag.memory.isSpawned) {
            // 全部阵亡，移除旗帜
            if (!creeps.length) {
                flag.remove()
                return false
            }

            return true
        }

        const configs = BattleConfig[flag.memory.config]
        if (!configs || creeps.length >= configs.length) {
            BattleSpawn.sortCreepsByDamage(flag)
            return (flag.memory.isSpawned = true)
        }

        if (
            flag.memory.creeps.length >= configs.length ||
            SpawnController.searchSpawnTaskByRole(flag._belongRoom, CreepRoles.teamMember).length > 0
        ) {
            return false
        }

        const config = configs[creeps.length]
        const boostData: CreepBoostData = {}
        const task: SpawnTask = {
            role: CreepRoles.teamMember,
            body: config.body,
            memory: { boost: { data: boostData, wait: true }, flag: flag.name },
        }

        // 添加 boost
        if (config.boostType) {
            const boostMap = levelBoostMap[config.boostType]
            // 遍历每种部件，如果该部件存在可以 boost 的类型，则添加 boost 数据
            getBodyPartTypes(config.body).forEach((part) => {
                if (!boostMap[part]) return

                boostData[part] = {
                    type: boostMap[part]!,
                    require: 50,
                    amount: 0,
                }
            })
        } else if (config.boostRes?.length) {
            const bodyPartTypeSet = new Set(getBodyPartTypes(config.body))
            // 遍历资源，如果该资源存在可以 boost 的部件，则添加 boost 数据
            config.boostRes.forEach((res) => {
                const part = ResourcePartMap[res]
                if (!bodyPartTypeSet.has(part)) return

                boostData[part] = {
                    type: res,
                    require: 50,
                    amount: 0,
                }
            })
        }

        const creepName = SpawnController.addSpawnTask(flag._belongRoom, task)
        if (creepName) {
            flag.memory.creeps.push(creepName)
        }

        return false
    }

    /**
     * 所有爬 renew 到接近满寿命
     */
    public static renewCreeps(flag: Flag) {
        if (flag.memory.isRenewed) return true

        const creeps = flag._creeps

        if (flag.memory.isSpawned && creeps.every((creep) => creep.ticksToLive && creep.ticksToLive > 1450)) {
            creeps.forEach((creep) => delete creep.memory.stand)
            return (flag.memory.isRenewed = true)
        }

        // 启用暂缓模式，暂缓最后一个 spawn 的低优先级爬生产
        SpawnController.addPostponeSpawnRoom(flag._belongRoom!.name)
        // 获取最后一个 spawn 用于 renew
        const postponeSpawn = SpawnController.getPostponeSpawn(flag._belongRoom!)
        if (!postponeSpawn) return false

        creeps.forEach((creep) => {
            if (creep.spawning) return

            const range = creep.pos.getRangeTo(postponeSpawn)

            if (range <= 1 && postponeSpawn.spawning) {
                delete creep.memory.stand
                goTo(creep, postponeSpawn.pos, { flee: true, range: 2 })
                return
            }

            // 寿命足的也靠近
            if (creep.ticksToLive! > 1460 && range < 4) {
                delete creep.memory.stand
                return
            }

            if (range <= 1) {
                creep.memory.stand = true
                postponeSpawn.renewCreep(creep)
            } else if (!postponeSpawn.spawning) {
                goTo(creep, postponeSpawn.pos)
            }
        })

        return false
    }

    /**
     * 等待 boost 完成
     */
    public static waitForBoost(flag: Flag) {
        if (flag.memory.isBoosted) return true

        const creeps = flag._creeps
        let allDone = true
        creeps.forEach((creep) => {
            delete creep.memory.stand

            // 取消 boost 等待状态
            if (creep.memory.boost && creep.memory.boost.wait) {
                delete creep.memory.boost.wait
            }
            if (creep.memory.boost && !creep.memory.boost.done) {
                allDone = false
            }
        })

        if (allDone) {
            flag.memory.isBoosted = true
        }
        return allDone
    }

    /**
     * 将爬按伤害从大到小排序
     */
    public static sortCreepsByDamage(flag: Flag) {
        const creeps = flag._creeps
        const damageMap = creeps.reduce((map, creep) => {
            map[creep.name] = BattleCalc.calcCreepDamage(creep)
            return map
        }, {} as { [creepName: string]: number })
        creeps.sort((a, b) => damageMap[b.name] - damageMap[a.name])
        flag.memory.creeps = creeps.map((creep) => creep.name)
    }
}

declare global {
    interface FlagMemory {
        /**
         * 是否孵化完毕
         */
        isSpawned?: boolean
        /**
         * 是否 renew 完毕
         */
        isRenewed?: boolean
        /**
         * 是否 boost 完毕
         */
        isBoosted?: boolean
        /**
         * 创建时间
         */
        createTime: number

        /**
         * 持续旗帜时间间隔
         */
        interval?: number
        /**
         * 持续旗帜出兵次数
         */
        count?: number
        /**
         * 持续旗帜等待时间，比如对面 sf 了需要等待
         */
        wait?: number
        /**
         * 持续旗帜提前结束出兵触发条件，unclaim 房间已放弃，safemode 房间进入安全模式，no-struct 房间没有建筑, 'none' 不提前结束。默认不填是 none
         */
        endTigger?: 'unclaim' | 'safemode' | 'no-struct' | 'none'
        /**
         * 上一个旗帜的创建时间
         */
        lastFlagCreateTime?: number
    }
}
